import { store } from 'app/store/store';
import { PartialAppConfig } from 'app/types/invokeai';
import React, {
  lazy,
  memo,
  PropsWithChildren,
  ReactNode,
  useEffect,
} from 'react';
import { Provider } from 'react-redux';
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
import Loading from '../../common/components/Loading/Loading';
import { socketMiddleware } from 'services/events/middleware';
import { Middleware } from '@reduxjs/toolkit';
import ImageDndContext from './ImageDnd/ImageDndContext';
import { $authToken, $baseUrl, $socketBase } from 'services/api/client';
import { logger } from 'app/logging/logger';
import { ThemeLocaleProvider } from '@tourfly/theme';
import { getSocket } from 'services/events/systemSocket';
// Localization
import '@tourfly/locales/i18n';
import { useTranslation } from 'react-i18next';
const App = lazy(() => import('./App'));
const mode = import.meta.env.MODE;
interface Props extends PropsWithChildren {
  baseUrl?: string;
  token?: string;
  socketBase?: string;
  config?: PartialAppConfig;
  headerComponent?: ReactNode;
  middleware?: Middleware[];
}
type ThemeLocaleProviderProps = {
  children: ReactNode;
  direction: 'ltr' | 'rtl';
};
const ThemeProvider = (props: ThemeLocaleProviderProps) => {
  if (mode === 'alone') {
    return (
      <ThemeLocaleProvider direction={props.direction}>
        {props.children}
      </ThemeLocaleProvider>
    );
  } else {
    return <>{props.children}</>;
  }
};
const InvokeAIUI = ({
  baseUrl,
  socketBase,
  token,
  config,
  headerComponent,
  middleware,
}: Props) => {
  const { i18n } = useTranslation();
  const direction = i18n.dir();
  const log = logger('system');

  useEffect(() => {
    log.info({ token, baseUrl, socketBase }, 'Received API Config');

    // configure API client token
    if (token) {
      $authToken.set(token);
    }

    // configure API client base url
    if (baseUrl) {
      $baseUrl.set(baseUrl);
    }

    if (socketBase) {
      $socketBase.set(socketBase);
    }

    // reset dynamically added middlewares
    resetMiddlewares();

    // TODO: at this point, after resetting the middleware, we really ought to clean up the socket
    // stuff by calling `dispatch(socketReset())`. but we cannot dispatch from here as we are
    // outside the provider. it's not needed until there is the possibility that we will change
    // the `apiUrl`/`token` dynamically.

    // rebuild socket middleware with token and apiUrl
    if (middleware && middleware.length > 0) {
      addMiddleware(socketMiddleware(), ...middleware);
    } else {
      addMiddleware(socketMiddleware());
    }

    return () => {
      // Reset the API client token and base url on unmount
      $baseUrl.set(undefined);
      $authToken.set(undefined);
      $socketBase.set(undefined);
      if (getSocket()) {
        getSocket()?.disconnect();
      }
    };
  }, [baseUrl, token, middleware, socketBase, log]);

  return (
    // <React.StrictMode>
    <Provider store={store}>
      <React.Suspense fallback={<Loading />}>
        <ThemeProvider direction={direction}>
          <ImageDndContext>
            <App config={config} headerComponent={headerComponent} />
          </ImageDndContext>
        </ThemeProvider>
      </React.Suspense>
    </Provider>
    // </React.StrictMode>
  );
};
InvokeAIUI.displayName = 'InvokeAIUI';

export default memo(InvokeAIUI);
